package com.xiaoqian.partyembassy.ui.fragment.map;

import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.EditText;

import com.amap.api.maps.AMap;
import com.amap.api.maps.CameraUpdate;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.MapView;
import com.amap.api.maps.TextureMapView;
import com.amap.api.maps.UiSettings;
import com.amap.api.maps.model.BitmapDescriptor;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.Circle;
import com.amap.api.maps.model.CircleOptions;
import com.amap.api.maps.model.GroundOverlay;
import com.amap.api.maps.model.GroundOverlayOptions;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.LatLngBounds;
import com.amap.api.maps.model.Marker;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.maps.model.Polyline;
import com.amap.api.maps.model.PolylineOptions;
import com.google.android.material.snackbar.Snackbar;
import com.indooratlas.android.sdk.IALocation;
import com.indooratlas.android.sdk.IALocationListener;
import com.indooratlas.android.sdk.IALocationManager;
import com.indooratlas.android.sdk.IALocationRequest;
import com.indooratlas.android.sdk.IAOrientationListener;
import com.indooratlas.android.sdk.IAOrientationRequest;
import com.indooratlas.android.sdk.IAPOI;
import com.indooratlas.android.sdk.IARegion;
import com.indooratlas.android.sdk.IARoute;
import com.indooratlas.android.sdk.IAWayfindingListener;
import com.indooratlas.android.sdk.IAWayfindingRequest;
import com.indooratlas.android.sdk.resources.IAFloorPlan;
import com.indooratlas.android.sdk.resources.IALatLng;
import com.indooratlas.android.sdk.resources.IALocationListenerSupport;
import com.indooratlas.android.sdk.resources.IAVenue;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.RequestCreator;
import com.squareup.picasso.Target;
import com.xiaoqian.partyembassy.R;
import com.xiaoqian.partyembassy.base.BaseFragment;
import com.xiaoqian.partyembassy.tools.CommonToolUtils;
import com.xiaoqian.partyembassy.view.DialogLoadingView;
import com.xiaoqian.partyembassy.view.LoadProgressDialog;
import com.xiaoqian.partyembassy.view.NumberPicker;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;


public class MapFragment extends BaseFragment implements NumberPicker.OnValueChangeListener{

    private AMap mMap;
    private NumberPicker map_floor_numberpick;
    private int mCurrentFloorValue = 0;
    private String[] floorArray = null;
    //private MapView mMapView;
    private IALocationManager mIALocationManager;
    private int mFloor;
    private Circle mCircle;
    private Marker mHeadingMarker;
    private Marker mDestinationMarker;
    private boolean mCameraPositionNeedsUpdating = true; // update on first location
    private IARoute mCurrentRoute;
    private Target mLoadTarget;
    private IAWayfindingRequest mWayfindingDestination;
    private GroundOverlay mGroundOverlay = null;
    private IARegion mOverlayFloorPlan = null;
    private IAVenue mVenue;
    private List<Marker> mPoIMarkers = new ArrayList<>();
    private List<Polyline> mPolylines = new ArrayList<>();
    private static final int MAX_DIMENSION = 2048;
    private TextureMapView textureMapView;
    private LoadProgressDialog dialogLoadingView;
    @Override
    protected int getLayoutId() {
        return R.layout.fragment_map;
    }
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        textureMapView = (TextureMapView) getView().findViewById(R.id.map);

        if (textureMapView != null) {
            textureMapView.onCreate(savedInstanceState);
            initMap();
//            aMap = textureMapView.getMap();
//            if (getCameraPosition() == null) {
//                aMap.moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition(getTarget(), 10, 0, 0)));
//            }else {
//                aMap.moveCamera(CameraUpdateFactory.newCameraPosition(getCameraPosition()));
//            }
        }
    }
    @Override
    protected void initParams() {
        mIALocationManager = IALocationManager.create(mContext);
        Location location = new Location("");
        location.setLatitude(24.486979180264);
        location.setLongitude(118.18703762512);
        IALocation s = IALocation.from(location);
        mIALocationManager.setLocation(s);
    }

    @Override
    protected void initView() {
        map_floor_numberpick = view.findViewById(R.id.map_floor_numberpick);
        map_floor_numberpick.setOnValueChangedListener(this);
        initFloorPickerData();
       dialogLoadingView = new LoadProgressDialog(mContext,"");
        dialogLoadingView.show();
        mHandler.sendEmptyMessageDelayed(0x01,3000);
    }
    Handler mHandler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            dialogLoadingView.dismiss();
        }
    };
    private void initMap() {
        if (mMap == null) {
            mMap = textureMapView.getMap();
        }

        mMap.setMyLocationEnabled(false);
        mMap.showIndoorMap(true);
        UiSettings uiSettings = mMap.getUiSettings();
        uiSettings.setZoomControlsEnabled(true);
        CameraUpdate cameraUpdate = CameraUpdateFactory.zoomTo(19);
        mMap.moveCamera(cameraUpdate);
        mMap.setOnMapClickListener(new AMap.OnMapClickListener() {
            @Override
            public void onMapClick(LatLng point) {
                if (mPoIMarkers.isEmpty()) {
                    // if PoIs exist, only allow wayfinding to PoI markers
                    setWayfindingTarget(point, true);
                }
            }
        });
        mMap.setOnMarkerClickListener(new AMap.OnMarkerClickListener() {
            @Override
            public boolean onMarkerClick(Marker marker) {
                // ignore clicks to artificial wayfinding target markers
                if (marker == mDestinationMarker)
                    return false;
                setWayfindingTarget(marker.getPosition(), false);
                // do not consume the event so that the popup with marker name is displayed
                return false;
            }
        });
    }
    private void setWayfindingTarget(LatLng point, boolean addMarker) {
        if (mMap == null) {
            Log.w("TAG", "map not loaded yet");
            return;
        }

        mWayfindingDestination = new IAWayfindingRequest.Builder()
                .withFloor(mFloor)
                .withLatitude(point.latitude)
                .withLongitude(point.longitude)
                .build();

        mIALocationManager.requestWayfindingUpdates(mWayfindingDestination, mWayfindingListener);

        if (mDestinationMarker != null) {
            mDestinationMarker.remove();
            mDestinationMarker = null;
        }

        if (addMarker) {
            mDestinationMarker = mMap.addMarker(new MarkerOptions()
                    .position(point)
                    .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE)));
        }
        Log.d("TAG", "Set destination: (" + mWayfindingDestination.getLatitude() + ", " +
                mWayfindingDestination.getLongitude() + "), floor=" +
                mWayfindingDestination.getFloor());

    }
        /**
         * 初始化楼层数据
         */
    private void initFloorPickerData() {
        mCurrentFloorValue = 0;
        String[] nameArr = getFloorNameArray();
        if (nameArr.length > 0) {
            // 设置灯关面板picker
            map_floor_numberpick.setMaxValue(nameArr.length - 1);
            map_floor_numberpick.setMinValue(0);
            map_floor_numberpick.setDisplayedValues(nameArr);
            map_floor_numberpick
                    .setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);
        }

    }
    /**
     * 获取楼层名称列表
     */
    private String[] getFloorNameArray() {
        floorArray = new String[5];
        for (int i = 0; i < 5; i++) {
            String floorName = i+"";
            if (TextUtils.isEmpty(floorName)) {
                floorArray[i] = "默认楼层";
            } else {
                floorArray[i] = floorName;
            }
        }
        return floorArray;
    }
    @Override
    public void onValueChange(NumberPicker picker, int oldVal, int newVal, EditText editText) {

    }
    @Override
    public void onResume() {
        super.onResume();
        Log.d("zh", "onResume进来了");
        textureMapView.onResume();
        mIALocationManager.requestLocationUpdates(IALocationRequest.create(), mListener);
        mIALocationManager.registerRegionListener(mRegionListener);
        mIALocationManager.registerOrientationListener(
                // update if heading changes by 1 degrees or more
                new IAOrientationRequest(1, 0),
                mOrientationListener);

        if (mWayfindingDestination != null) {
            mIALocationManager.requestWayfindingUpdates(mWayfindingDestination, mWayfindingListener);
        }
    }
    private IAWayfindingListener mWayfindingListener = new IAWayfindingListener() {
        @Override
        public void onWayfindingUpdate(IARoute route) {
            mCurrentRoute = route;
            if (hasArrivedToDestination(route)) {
                // stop wayfinding
                showInfo("You're there!");
                mCurrentRoute = null;
                mWayfindingDestination = null;
                mIALocationManager.removeWayfindingUpdates();
            }
            updateRouteVisualization();
        }
    };
    private void showInfo(String text) {
        final Snackbar snackbar = Snackbar.make(view.findViewById(android.R.id.content), text,
                Snackbar.LENGTH_INDEFINITE);
        snackbar.setAction(R.string.button_close, new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                snackbar.dismiss();
            }
        });
        snackbar.show();
    }

    private boolean hasArrivedToDestination(IARoute route) {
        // empty routes are only returned when there is a problem, for example,
        // missing or disconnected routing graph
        if (route.getLegs().size() == 0) {
            return false;
        }

        final double FINISH_THRESHOLD_METERS = 8.0;
        double routeLength = 0;
        for (IARoute.Leg leg : route.getLegs()) routeLength += leg.getLength();
        return routeLength < FINISH_THRESHOLD_METERS;
    }
    private IAOrientationListener mOrientationListener = new IAOrientationListener() {
        @Override
        public void onHeadingChanged(long timestamp, double heading) {
            updateHeading(heading);
        }

        @Override
        public void onOrientationChange(long timestamp, double[] quaternion) {
            // we do not need full device orientation in this example, just the heading
        }
    };
    private void updateHeading(double heading) {
        if (mHeadingMarker != null) {
            mHeadingMarker.setRotateAngle((float)heading);
        }
    }
    /**
     * Listener that changes overlay if needed
     */
    private IARegion.Listener mRegionListener = new IARegion.Listener() {
        @Override
        public void onEnterRegion(final IARegion region) {
            if (region.getType() == IARegion.TYPE_FLOOR_PLAN) {
                Log.d("TAG", "enter " + region.getFloorPlan().toString());
                IAFloorPlan floorPlan = region.getFloorPlan();

                IAVenue venue = region.getVenue();
                if(null == venue){
                    Log.e("ss11","null");
                }else{
                    Log.e("ss11",venue.toString());
                }

                Log.d("TAG", "enter floor plan " + region.getId());
                mCameraPositionNeedsUpdating = true; // entering new fp, need to move camera
                if (mGroundOverlay != null) {
                    mGroundOverlay.remove();
                    mGroundOverlay = null;
                }
                mOverlayFloorPlan = region; // overlay will be this (unless error in loading)
                fetchFloorPlanBitmap(region.getFloorPlan());
                setupPoIs(mVenue.getPOIs(), region.getFloorPlan().getFloorLevel());
            } else if (region.getType() == IARegion.TYPE_VENUE) {
                Log.e("ss222","null");
                mVenue = region.getVenue();
            }
        }

        @Override
        public void onExitRegion(IARegion region) {
        }

    };
    private void setupPoIs(List<IAPOI> pois, int currentFloorLevel) {
        Log.d("TAG", pois.size() + " PoI(s)");
        // remove any existing markers
        for (Marker m : mPoIMarkers) {
            m.remove();
        }
        mPoIMarkers.clear();
        if(CommonToolUtils.isEmpty(pois)){
            List<LatLng> latLngs = new ArrayList<>();

            for (IAPOI poi : pois) {

                if (poi.getFloor() == currentFloorLevel) {
                    latLngs.add(new LatLng(poi.getLocation().latitude, poi.getLocation().longitude));
                    mPoIMarkers.add(mMap.addMarker(new MarkerOptions()
                            .title(poi.getName())
                            .position(new LatLng(poi.getLocation().latitude, poi.getLocation().longitude))
                            .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))));
                   // mPolylines.add(mMap.addPolyline(opt));
                }
            }
            mMap.addPolyline(new PolylineOptions().
                    addAll(latLngs).width(10).color(Color.argb(255, 255, 48, 48)));

        }

    }
    /**
     * Download floor plan using Picasso library.
     */
    private void fetchFloorPlanBitmap(final IAFloorPlan floorPlan) {

        if (floorPlan == null) {
            Log.e("TAG", "null floor plan in fetchFloorPlanBitmap");
            return;
        }
        final String url = floorPlan.getUrl();
        Log.d("TAG", "loading floor plan bitmap from "+url);
        mLoadTarget = new Target() {
            @Override
            public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                Log.d("TAG", "onBitmap loaded with dimensions: " + bitmap.getWidth() + "x"
                        + bitmap.getHeight());
                if (mOverlayFloorPlan != null && floorPlan.getId().equals(mOverlayFloorPlan.getId())) {
                    Log.d("TAG", "showing overlay");
                    setupGroundOverlay(floorPlan, bitmap);
                }
            }
            @Override
            public void onPrepareLoad(Drawable placeHolderDrawable) {
                // N/A
            }
            @Override
            public void onBitmapFailed(Drawable placeHolderDrawable) {
                showInfo("Failed to load bitmap");
                mOverlayFloorPlan = null;
            }
        };

        RequestCreator request = Picasso.with(mContext).load(url);

        final int bitmapWidth = floorPlan.getBitmapWidth();
        final int bitmapHeight = floorPlan.getBitmapHeight();

        if (bitmapHeight > MAX_DIMENSION) {
            request.resize(0, MAX_DIMENSION);
        } else if (bitmapWidth > MAX_DIMENSION) {
            request.resize(MAX_DIMENSION, 0);
        }

        request.into(mLoadTarget);
    }
    /**
     * Sets bitmap of floor plan as ground overlay on Google Maps
     */
    private void setupGroundOverlay(IAFloorPlan floorPlan, Bitmap bitmap) {
        if (mGroundOverlay != null) {
            mGroundOverlay.remove();
        }
        if (mMap != null) {
            BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromBitmap(bitmap);
            IALatLng iaLatLng = floorPlan.getCenter();
            mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(iaLatLng.latitude,
                    iaLatLng.longitude), 20));//
            LatLng center = new LatLng(iaLatLng.latitude, iaLatLng.longitude);
            GroundOverlayOptions fpOverlay = new GroundOverlayOptions()
                    .zIndex(0.0f)
                    .image(bitmapDescriptor)
                    .transparency( 0.5f)
                    .position(center,floorPlan.getWidthMeters(), floorPlan.getHeightMeters()).bearing(floorPlan.getBearing());
           mGroundOverlay = mMap.addGroundOverlay(fpOverlay);

        }
    }
    @Override
    public void onPause() {
        super.onPause();
        Log.d("zh", textureMapView + ":onPause");
        textureMapView.onPause();
        mIALocationManager.removeLocationUpdates(mListener);
        mIALocationManager.unregisterRegionListener(mRegionListener);
        mIALocationManager.unregisterOrientationListener(mOrientationListener);

        if (mWayfindingDestination != null) {
            mIALocationManager.removeWayfindingUpdates();
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d("zh", textureMapView + ":onSaveInstanceState");
        textureMapView.onSaveInstanceState(outState);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("zh", textureMapView + ":onDestroy进来了");
        textureMapView = null;
        if(null != textureMapView){
            textureMapView.onDestroy();
        }
       if(null != mIALocationManager){
           mIALocationManager.destroy();
       }
    }



    /**
     * Listener that handles location change events.
     */
    private IALocationListener mListener = new IALocationListenerSupport() {

        /**
         * Location changed, move marker and camera position.
         */
        @Override
        public void onLocationChanged(IALocation location) {

            Log.d("TAG", "new location received with coordinates: " + location.getLatitude()
                    + "," + location.getLongitude());

            if (mMap == null) {
                // location received before map is initialized, ignoring update here
                return;
            }

            final LatLng center = new LatLng(location.getLatitude(), location.getLongitude());

            final int newFloor = location.getFloorLevel();
            if (mFloor != newFloor) {
               updateRouteVisualization();
            }
            mFloor = newFloor;

            showLocationCircle(center, location.getAccuracy());

            // our camera position needs updating if location has significantly changed
            if (mCameraPositionNeedsUpdating) {
                mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(center, 17.5f));
                mCameraPositionNeedsUpdating = false;
            }
        }
    };
    private void showLocationCircle(LatLng center, double accuracyRadius) {
        if (mCircle == null) {
            // location can received before map is initialized, ignoring those updates
            if (mMap != null) {
                mCircle = mMap.addCircle(new CircleOptions()
                        .center(center)
                        .radius(accuracyRadius)
                        .fillColor(0x201681FB)
                        .strokeColor(0x500A78DD)
                        .zIndex(1.0f)
                        .visible(true)
                        .strokeWidth(5.0f));
                mHeadingMarker = mMap.addMarker(new MarkerOptions()
                        .position(center)
                        .icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_launcher))
                        .anchor(0.5f, 0.5f)
                        );
            }
        } else {
            // move existing markers position to received location
            mCircle.setCenter(center);
            mHeadingMarker.setPosition(center);
            mCircle.setRadius(accuracyRadius);
        }
    }
    /**
     * Visualize the IndoorAtlas Wayfinding route on top of the Google Maps.
     */
    private void updateRouteVisualization() {

        clearRouteVisualization();

        if (mCurrentRoute == null) {
            return;
        }

        for (IARoute.Leg leg : mCurrentRoute.getLegs()) {

            if (leg.getEdgeIndex() == null) {
                // Legs without an edge index are, in practice, the last and first legs of the
                // route. They connect the destination or current location to the routing graph.
                // All other legs travel along the edges of the routing graph.

                // Omitting these "artificial edges" in visualization can improve the aesthetics
                // of the route. Alternatively, they could be visualized with dashed lines.
                continue;
            }

            PolylineOptions opt = new PolylineOptions();
            opt.add(new LatLng(leg.getBegin().getLatitude(), leg.getBegin().getLongitude()));
            opt.add(new LatLng(leg.getEnd().getLatitude(), leg.getEnd().getLongitude()));

            // Here wayfinding path in different floor than current location is visualized in
            // a semi-transparent color
            if (leg.getBegin().getFloor() == mFloor && leg.getEnd().getFloor() == mFloor) {
                opt.color(0xFF0000FF);
            } else {
                opt.color(0x300000FF);
            }

            mPolylines.add(mMap.addPolyline(opt));
        }
    }
    /**
     * Clear the visualizations for the wayfinding paths
     */
    private void clearRouteVisualization() {
        for (Polyline pl : mPolylines) {
            pl.remove();
        }
        mPolylines.clear();
    }
}